import { Injectable } from '@angular/core';
import { LyricLine, Lyric } from 'src/app/routes/entity';
import { zip, from, Observable } from 'rxjs';
import { skip } from 'rxjs/operators';

/** [00:01.000] */
const timeExp = /\[(\d{2}):(\d{2})(?:\.(\d{2,3}))?\]/;

@Injectable()
export class LyricParseService {

  /**
   * 解析歌词
   *
   * @param lyric 歌词信息
   */
  parseLyric(lyric: Lyric): LyricLine[] {
    if (lyric.tlyric) {
      return this.generateTlyricLines(lyric.lyric, lyric.tlyric);
    }
    return this.generateLyricLines(lyric.lyric);
  }

  /**
   * 生成歌词行集合
   * 
   * @param lyric 歌词串
   */
  private generateLyricLines(lyric: string): LyricLine[] {
    if (lyric) {
      const lines = lyric.split('\n');
      return lines.map(line => this.makeLyricLine(line))
        .filter(e => e !== null);
    }
    return [];
  }

  /**
   * 生成歌词行集合
   * 
   * @param tlyric 翻译后的歌词串
   */
  private generateTlyricLines(lyric: string, tlyric: string): LyricLine[] {
    const lines = lyric.split('\n').filter(item => timeExp.exec(item) !== null);
    const tlines = tlyric.split('\n').filter(item => timeExp.exec(item) !== null);
    const moreline = lines.length - tlines.length;
    let tempArr = [];
    // 将数量最少的放在数组末尾
    if (moreline >= 0) {
      tempArr = [lines, tlines];
    } else {
      tempArr = [tlines, lines];
    }
    // 获取最少数组的第一个索引对应的时间段
    const first = timeExp.exec(tempArr[1][0])[0];
    // 获取最少数组第一个索引的时间段对应最长数组中的索引
    const skipIndex = tempArr[0].findIndex(item => {
      const exec = timeExp.exec(item);
      if (exec) {
        return exec[0] === first;
      }
    });
    const skipLength = skipIndex === -1 ? 0 : skipIndex;
    // 解析多余的歌词行
    const skipItems = tempArr[0].slice(0, skipLength).map(e => this.makeLyricLine(e));
    // 合并剩下的歌词行
    let zipLines: Observable<any>;
    if (moreline > 0) {
      zipLines = zip(from(lines).pipe(skip(skipLength)), from(tlines));
    } else {
      zipLines = zip(from(lines), from(tlines).pipe(skip(skipLength)));
    }
    const lyricLines = [];
    zipLines.subscribe(([line, tline]) => lyricLines.push(this.makeLyricLine(line, tline)));
    return [...skipItems, ...lyricLines].filter(e => e !== null);
  }

  /**
   * 生成单行歌词对象
   * 
   * @param line 单行歌词
   */
  private makeLyricLine(line: string, tline = ''): LyricLine {
    const result = timeExp.exec(line);
    if (result) {
      const text = line.replace(timeExp, '').trim();
      const textCN = tline ? tline.replace(timeExp, '') : '';
      if (text) {
        // 解析时间
        const lastResultStr = result[3] || '00';
        const lastResult = lastResultStr.length > 2 ? parseInt(lastResultStr) : parseInt(lastResultStr) * 10;
        const time = Number(result[1]) * 60 * 1000 + Number(result[2]) * 1000 + lastResult;
        return { text, textCN, time };
      }
    }
    return null;
  }
}
